﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net.Sockets;
using System.Diagnostics;

namespace Connector
{
    public class ConnectorClient
    {
        public string m_host;
        public int m_port;
        public Socket m_client;
        public event Action<byte[]> m_ReceiveMsgHandler;
        public event Action m_OnCloseHandler;
        private int m_MTU = 1500;
        private int m_leftdatalen = 0;
        private List<byte> m_datacache;
        private string m_status;
        public ConnectorClient()
        {
            m_datacache = new List<byte>();
            m_client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        }
        public bool Connect(string host, int port)
        { 
            try
            {
                m_client.Connect(host, port);
            }
            catch (SocketException e)
            {
                Debug.WriteLine(string.Format("ConnectorClient:Connect error {0}.", e.Message));
                return false;
            }
            m_host = host;
            m_port = port;
            return true;
        }
        private void OnClose()
        {
            if (m_OnCloseHandler != null)
            {
                m_OnCloseHandler.Invoke();
            }
        }
        public void Close()
        {
            OnClose();
            m_client.Close();
            m_host = "";
            m_port = 0;
            Debug.WriteLine("Connector::Close");
            m_client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        }
        public bool IsConnected()
        {
            return m_client.Connected;
        }
        public void SendData(byte[] data)
        {
            if (!IsConnected())
                return;
            int len = data.Length;
            byte[] head = ConnectorProto.IntToByte(len);
            int numSented = 0;
            try
            {
                numSented = m_client.Send(head);
            }
            catch (SocketException e)
            {
                Debug.WriteLine("Connector::SendData " + e.Message);
                Close();
                return;
            }
            int sumSented = 0;
            if (numSented != 4)
            {
                Debug.WriteLine("Connector Send head failed");
                return;
            }

            do
            {
                try
                {
                    numSented = m_client.Send(data, sumSented, len - sumSented, SocketFlags.None);
                }
                catch (SocketException e)
                {
                    Debug.WriteLine("Connector::SendData " + e.Message);
                    Close();
                    break;
                }
                sumSented += numSented;
            } while (sumSented < len);
        }

        private bool ReceiveData(int len)
        {
            int mLen = Math.Min(m_MTU, len);
            bool finished = false;
            byte[] buffer = new byte[m_MTU];
            int numGet = 0;
            int sumGet = 0;
            m_client.Blocking = false;
            while (!finished)
            {
                if (!m_client.Poll(0, SelectMode.SelectRead))
                {
                    //没有数据可读
                    break;
                }
                try
                {
                    numGet = m_client.Receive(buffer, mLen, SocketFlags.None);
                    sumGet += numGet;
                    if (numGet != 0 )
                    {
                        for (int i = 0; i < numGet; ++i)
                            m_datacache.Add(buffer[i]);
                        mLen = len - sumGet;
                        finished = mLen == 0;
                        mLen = Math.Min(m_MTU, mLen);
                    }
                    else
                    {
                        break;
                    }
                }
                catch (SocketException e)
                {
                    m_status = "closed";
                    Debug.Write("Connector::ReceiveData " + e.Message);
                    break;
                }
            }
            return finished;
        }
        public void Tick()
        {
            if (!IsConnected())
                return;
            if (m_leftdatalen == 0)
            {
                bool finished = ReceiveData(sizeof(int));
                if (finished)
                {
                    byte[] data = m_datacache.ToArray();
                    m_leftdatalen = ConnectorProto.ByteToInt(data);
                    m_datacache.Clear();
                    //MobileDebugLogger.Log("Connector Start receive new package");
                }
                else if (m_status == "closed")
                {
                    Close();
                }
            }
            else
            {
                bool finished = ReceiveData(m_leftdatalen - m_datacache.Count);
                if (finished)
                {
                    byte[] data = m_datacache.ToArray();
                    m_datacache.Clear();
                    m_leftdatalen = 0;
                    //MobileDebugLogger.Log("Connector End receive new package");
                    m_ReceiveMsgHandler.Invoke(data);
                }
                else if (m_status == "closed")
                {
                    Close();
                }
            }
        }
    }
}
